#include "Evironment.h"
#include "Actions.h"
#include "PathFinder.h"
#include "SimpleMap.h"
#include <math.h>
namespace Core
{
	namespace GameLogic
	{
		typedef TEvironment<SimpleMap> Evironment;
		inline SimpleMap& GetMap()
		{
			return Evironment::getInstance()->GetScene().GetMap();
		}
		Move::Move(Element* e,ParamList* list)
			:Action(e,list),x(e->GetPosition().x),y(e->GetPosition().y),path_in_use(0)
		{
			
			try
			{
				ParamList& p=*list;
				speed=(p["speed"].GetDouble());
			}
			catch(std::exception e)
			{
				exit(0);
			}
		}
		void Move::PreExecute(ParamList *p)
		{//init the x,y or they will get the wrong number;
			x=receiver->GetPosition().x;
			y=receiver->GetPosition().y;
		}
	
		void Move::Execute()
		{
			Core::Position& des=mStep;
			Core::Position now=receiver->GetPosition();
			x=now.x;
			y=now.y;
			double dx,dy;
			if(abs(now.x-des.x)<speed&&abs(now.y-des.y)<speed)
			{
				if(pPos==paths[path_in_use].end())
				{
					receiver->SetToDefault();
					now.x=des.x;
					now.y=des.y;
					goto setP;
				}
				else
				{//if can reach the grid in less than one frame, then reach it.If not, will cause problem
					
					double d;
					dx=des.x-now.x;
					dy=des.y-now.y;
					
					d=speed-dx-dy;
					
					now=des;
					//refrash x and y, remember to refrash x and y when set position in other way
					x=now.x;
					y=now.y;
					receiver->SetPosition(now);

					des=GetMap().TileToGrid(pPos->pos);
					
					//when reach the grid, there is still some speed left ,go on for a while
					dy=des.y-now.y;
					dx=des.x-now.x;
					double td=sqrt(dx*dx+dy*dy);

					dy=dy/td*d;
					dx=dx/td*d;
					x+=dx;
					y+=dy;
					now.x=(int)x;
					now.y=(int)y;
					
					pPos++;
					goto setD;
				}
			}

			
			dy=des.y-now.y;
			dx=des.x-now.x;
			double d=sqrt(dx*dx+dy*dy);
			
			dy=dy/d*speed;
			dx=dx/d*speed;
			x+=dx;
			y+=dy;
			now.x=(int)x;
			now.y=(int)y;
			
setD:		if( abs(dx) > abs(dy) )
			{
				if( dx > 0 ) receiver->SetDir(Element::RIGHT);
				else if( dx < 0) receiver->SetDir(Element::LEFT);
			}
			else 
			{
				if( dy > 0 ) receiver->SetDir(Element::DOWN);
				else if (dy < 0) receiver->SetDir(Element::UP);
			}
			/*now.x=des.x;
			now.y=des.y;*/

setP:		receiver->SetPosition(now);
			

		}

		bool Move::SelfCheck(ParamList* list)
		{//Use the spear vector<WayPoint> to find path. If there is a path, use it. Or Continue to previous move
			Position mDes;
			Position recePos=receiver->GetPosition();
			boost::ptr_list<Core::WayPoint>& path=this->paths[path_in_use==0?1:0];
			try
			{
				ParamList& p=*list;
				mDes=(p["des"].GetPosition());
				//des=e->PositionOnGrid(des);
			}
			catch(std::exception e)
			{
				exit(0);
			}
			if(mDes==recePos) return false;
			SimpleMap* e=&GetMap();
			Core::Util::PathFinder<SimpleMap::LogicPart> finder((e->GetLogicMap()));
			
			finder.GetPath(e->BlockPosition(recePos),e->BlockPosition(mDes),path);
			if(path.size()>1)
			{
				/*if(this->mStep != this->receiver->GetPosition())
					path.push_front(new WayPoint(mStep,0,0));*/
				paths[path_in_use].clear();
				path_in_use=~path_in_use & 1;
				pPos=path.begin();
				//If there is a path, judge the direction. If it is westnorth or westsouth, we need to modify it 
				//for the float problem:
				boost::ptr_list<Core::WayPoint>::iterator npPos;
				npPos=pPos;
				npPos++;

				Position testpos=pPos->pos;
				Position tpos=e->TileToGrid(pPos->pos);
				if( tpos.y < recePos.y && npPos->pos.y==pPos->pos.y && npPos->pos.x!=pPos->pos.x 
					|| tpos.x < recePos.x && npPos->pos.x==pPos->pos.x && npPos->pos.y!=pPos->pos.y)
				{
					int x=tpos.x;
				}
				else
					pPos++;
				mStep=e->TileToGrid(pPos->pos);
				
				pPos++;
				return true;
			}
			else
			{
				return false;
			}
		}
		std::string Move::GetId()
		{
			return "move";
		}
	}
}